#pragma once

#include <string>
#include <iostream>
#include <memory>
#include <jsoncpp/json/json.h>

// #define SelfDefine 0

const static std::string ProtSep = " ";
const static std::string LineBreakSep = "\n";
 
// 封装（"len\nx op y\n" 中\n 不属于报文的一部分，是一种约定）
std::string Encode(const std::string &message)
{
    std::string len = std::to_string(message.size());
    std::string package = len + LineBreakSep + message + LineBreakSep;
    return package;
}

// 解包（"len\nx op y\n" 中\n 不属于报文的一部分，是一种约定）
bool Decode(std::string &package, std::string *message)
{
    // 无法保证package就是一个独立的完整的报文
    // 下面是一些可能的情况
    // "l"
    // "len"
    // "len\n"
    // "len\nx"
    // "len\nx op"
    // "len\nx op y"
    // "len\nx op y\n"
    // "len\nx op y\nlen"
    // 除了解包，我还想判断报文的完整性，能否正确处理具有“边界”的报文
    auto pos = package.find(LineBreakSep);
    if(pos == std::string::npos)    // 可能情况："l" "len"
        return false;
    std::string len = package.substr(0, pos);
    int messagelen = std::stoi(len);
    int total = len.size() + messagelen + 2*LineBreakSep.size();
    if(package.size() < total)      // 可能情况："len\nx op" "len\nx op y"
        return false;
    // 至少package内部一定有一个完整的报文了！
    *message = package.substr(pos+LineBreakSep.size(), messagelen);
    package.erase(0, total);    // 把一段处理过的完整报文删掉
    return true;
}


class Request
{
public:
    Request()
    {}

    Request(int x, int y, char op)
        :_data_x(x)
        ,_data_y(y)
        ,_oper(op)
    {}

    void Debug()
    {
        std::cout << "data_x: " << _data_x << std::endl;
        std::cout << "data_y: " << _data_y << std::endl;
        std::cout << "oper: " << _oper << std::endl;
    }

    // 调试用
    void Inc()
    {
        _data_x++;
        _data_y++;
    }

    // 序列化（结构化数据->字符串）
    bool Serialize(std::string *out)
    {
    #ifdef SelfDefine
        *out = std::to_string(_data_x) + ProtSep + _oper + ProtSep + std::to_string(_data_y);
        return true;
    #else
        // 这里可以使用jsoncpp等库来序列化
        Json::Value root;
        root["data_x"] = _data_x;
        root["data_y"] = _data_y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        *out = writer.write(root);
        return true;
    #endif
    }

    // 反序列化
    bool Deserialize(std::string &in)
    {
    #ifdef SelfDefine
        auto left = in.find(ProtSep);
        if(left == std::string::npos)
            return false;
        auto right = in.rfind(ProtSep);
        if(right == std::string::npos)
            return false;
        
        _data_x = std::stoi(in.substr(0, left));
        _data_y = std::stoi(in.substr(right+ProtSep.size()));
        std::string oper = in.substr(left+ProtSep.size(), right-(left+ProtSep.size()));
        if(oper.size() != 1)
            return false;

        _oper = oper[0];
        return true;
    #else
        // 这里可以使用jsoncpp等库来反序列化
        Json::Value root;
        Json::Reader reader;
        if(!reader.parse(in, root))
            return false;

        _data_x = root["data_x"].asInt();
        _data_y = root["data_y"].asInt();
        _oper = root["oper"].asInt();   // 字符也是以int存储的
        return true;
    #endif
    }

    int GetX() { return _data_x; }
    int GetY() { return _data_y; }
    char GetOper() { return _oper; }

private:
    // _data_x _oper _data_y
    int _data_x;    // 第一个参数
    int _data_y;    // 第二个参数
    char _oper;     // + - * / % 
};  

class Response
{
public:
    Response()
    {}

    Response(int result, int code)
        : _result(result)
        , _code(code)
    {} 

    // 序列化（结构化数据->字符串）
    bool Serialize(std::string *out)
    {
    #ifdef SelfDefine
        *out = std::to_string(_result) + ProtSep + std::to_string(_code);
        return true;
    #else
        // 这里可以使用jsoncpp等库来序列化
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;
        *out = writer.write(root);
        return true;
    #endif
    }

    // 反序列化
    bool Deserialize(std::string &in)
    {
    #ifdef SelfDefine
        auto pos = in.find(ProtSep);
        if(pos == std::string::npos)
            return false;
        
        _result = std::stoi(in.substr(0, pos));
        _code = std::stoi(in.substr(pos+ProtSep.size()));
        
        return true;
    #else
        // 这里可以使用jsoncpp等库来反序列化
        Json::Value root;
        Json::Reader reader;
        if(!reader.parse(in, root))
            return false;

        _result = root["result"].asInt();
        _code = root["code"].asInt();
        return true;
    #endif
    }

    void SetResult(int result) { _result = result; }
    void SetCode(int code) { _code = code; }

    int GetResult() { return _result; }
    int GetCode() { return _code; }

private:
    int _result;     // 运算结果
    int _code;       // 运算状态
};

// 简单的工厂模式
class Factory
{
public:
    std::shared_ptr<Request> BuildRequest()
    {
        return std::make_shared<Request>();
    }
    std::shared_ptr<Request> BuildRequest(int x, int y, char op)
    {
        return std::make_shared<Request>(x, y, op);
    }
    std::shared_ptr<Response> BuildResponse()
    {
        return std::make_shared<Response>();
    }
    std::shared_ptr<Response> BuildResponse(int result, int code)
    {
        return std::make_shared<Response>(result, code);
    }
};